<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>&lt;webview&gt; Demo</title>
    <style>
      html,
      body {
        margin: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
        display: flex;
        flex-flow: column;
        font-size: 14px;
      }
      .title-bar,
      .address-bar,
      .find-bar {
        display: flex;
        flex-flow: row;
        align-items: center;
        padding: 5px 10px;
        background-color: #f7f7f7;
        border-bottom: 1px solid #ccc;
      }
      #favicon {
        width: 16px;
        height: 16px;
        margin-right: 4px;
      }
      #title {
        flex: auto;
      }
      #address {
        flex: auto;
      }
      .find-bar {
        justify-content: flex-end;
      }
      #findResults {
        padding: 0 10px;
      }
      .content {
        flex: auto;
        display: flex;
        flex-flow: row;
      }
      #webview {
        flex: 2;
      }
      #devTools {
        flex: 1;
        border-left: 1px solid #ccc;
      }
    </style>
    <!-- prettier-ignore -->
    <style>
      .hide { display: none; }
      .disabled { opacity: 0.5; pointer-events: none; }
      body {
        &.loading {
          & [data-name="reload"] { display: none; }
          & [data-name="stop"] { display: inline-block; }
        }
        &.can-go-back [data-name="back"],
        &.can-go-forward [data-name="forward"],
        &.find-matches :is([data-name="findPrev"], [data-name="findNext"])
          { opacity: 1; pointer-events: auto; }
        &.show-find-bar .find-bar { display: flex; }
        &.show-dev-tools #devTools { display: block; }
      }
    </style>
  </head>
  <body class="">
    <div class="title-bar">
      <img id="favicon" src="#" />
      <label id="title">标题</label>
    </div>
    <div class="address-bar">
      <button data-name="back" class="disabled">返回</button>
      <button data-name="forward" class="disabled">前进</button>
      <button data-name="reload">刷新</button>
      <button data-name="stop" class="hide">停止</button>
      <input id="address" type="text" />
      <button data-name="toggleFindBar">查找</button>
      <button data-name="toggleDevTools">开发者工具</button>
    </div>
    <div class="find-bar hide">
      <div>查找：</div>
      <input id="searchText" type="text" />
      <div id="findResults">0/0</div>
      <button data-name="findPrev" class="disabled">上一个</button>
      <button data-name="findNext" class="disabled">下一个</button>
      <button data-name="stopFinding">结束</button>
    </div>
    <div class="content">
      <webview id="webview" src="https://www.baidu.com"></webview>
      <webview id="devTools" src="about:blank" class="hide"></webview>
    </div>
    <script>
      const bodyClass = document.body.classList;

      // const observer = new MutationObserver(() => {
      //   address.value = webview.src;
      // });
      // observer.observe(webview, { attributes: true });

      const browser = {
        back() {
          webview.back(); // 返回
        },
        forward() {
          webview.forward(); // 前进
        },
        reload() {
          webview.reload(); // 刷新
        },
        stop() {
          webview.stop(); // 停止
        },
        navigate(url) {
          if (url === "about:blank") {
            // 自定义空白页
            // webview.src = "blank.html";

            // 加载数据网址
            webview.loadDataWithBaseUrl(
              `data:text/html;charset=UTF-8,<html>
                <head><title>空白页</title></head>
                <body>啥都莫得</body>
              </html>`, // 数据网址
              url, // 基础网址
              url // 虚拟网址
            );
          } else {
            // 自动添加协议头
            if (!/^http(s?):\/\//i.test(url)) url = "https://" + url;
            webview.src = url;
          }
        },
        toggleFindBar() {
          const isShow = bodyClass.toggle("show-find-bar");
          if (isShow) {
            webview.executeScript(
              // 获取内嵌页面选中的文本
              { code: `window.getSelection().toString()` },
              ([selectionText]) => {
                if (selectionText) searchText.value = selectionText;
                // 查找输入框获得焦点并选中内容
                searchText.focus();
                searchText.selectionStart = 0;
                searchText.selectionEnd = searchText.value.length;
                // 如果查找输入框有内容，自动执行一次查找
                if (searchText.value) this.find(searchText.value, false);
              }
            );
          } else {
            webview.stopFinding();
          }
        },
        find(searchText, backward = false) {
          webview.find(searchText, { backward }, (results) => {
            const { numberOfMatches, activeMatchOrdinal } = results;
            findResults.textContent = activeMatchOrdinal + "/" + numberOfMatches;
            bodyClass.toggle("find-matches", numberOfMatches > 0);
          });
        },
        findPrev() {
          this.find(searchText.value, true);
        },
        findNext() {
          this.find(searchText.value, false);
        },
        stopFinding() {
          webview.stopFinding();
          bodyClass.remove("show-find-bar");
        },
        toggleDevTools() {
          const isShow = bodyClass.toggle("show-dev-tools");
          if (isShow) {
            webview.showDevTools(true, devTools);
          } else {
            webview.showDevTools(false);
            devTools.src = "about:blank";
          }
        },
      };

      // 按钮点击
      document.querySelectorAll("button[data-name]").forEach((el) => {
        el.addEventListener("click", () => {
          browser[el.dataset.name]?.();
        });
      });

      // 地址栏回车
      address.addEventListener("keydown", (e) => {
        if (!e.repeat && e.key === "Enter") {
          browser.navigate(address.value);
        }
      });

      // 查找输入框输入
      searchText.addEventListener("input", (e) => {
        browser.find(searchText.value, false);
      });

      const webviewEvents = {
        // 发生文档加载
        loadcommit({ isTopLevel, url }) {
          if (isTopLevel) {
            address.value = webview.src;
            bodyClass.add("loading");
            bodyClass.toggle("can-go-back", webview.canGoBack());
            bodyClass.toggle("can-go-forward", webview.canGoForward());
          }
        },
        // 文档加载完成
        loadstop() {
          bodyClass.remove("loading");

          // webview.executeScript(
          //   {
          //     code: `// 返回页面的图标、标题、URL
          //       ({
          //         favicon: document.querySelector('link[rel="shortcut icon"],link[rel="icon"]')?.href || location.origin + "/favicon.ico",
          //         title: document.title,
          //         url: location.href,
          //       })`,
          //     // file: "myscript.js",
          //   },
          //   ([data]) => {
          //     // console.log(data);
          //     favicon.src = data.favicon;
          //     title.textContent = data.title;
          //   }
          // );

          // 构建消息通道
          webview.executeScript({
            code: `
                let source;
                // 侦听来自应用的消息
                window.addEventListener("message", (event) => {
                  if (event.data === "Hi, webview!") {
                    // 缓存应用窗口 window 引用
                    source = event.source;
                    // 内嵌页面 → 应用（回传消息）
                    event.source.postMessage({
                      type: "webview_info",
                      data: {
                        favicon: document.querySelector('link[rel="shortcut icon"],link[rel="icon"]')?.href || location.origin + "/favicon.ico",
                        title: document.title,
                        url: location.href,
                      }
                    }, "*");
                  }
                });
              `,
          });

          // 页面 → 内嵌页面（发送初始化消息）
          webview.contentWindow.postMessage("Hi, webview!", "*");
        },
        // 加载失败或取消加载
        loadabord() {
          bodyClass.remove("loading");
        },
        // 模态弹框
        dialog(e) {
          const { dialog, messageType, messageText, defaultPromptText } = e;
          switch (messageType) {
            case "alert":
              alert(messageText);
              dialog.ok();
              break;
            case "confirm":
              dialog[confirm(messageText) ? "ok" : "cancel"]();
              break;
            case "prompt":
              const result = prompt(messageText, defaultPromptText);
              dialog[typeof result === "string" ? "ok" : "cancel"](result);
              break;
            default:
          }
        },
        // 打开新窗口
        newwindow(e) {
          webview.src = e.targetUrl;
        },
        // 自行关闭
        close() {
          browser.navigate("about:blank");
        },
      };
      Object.entries(webviewEvents).forEach(([eventName, handler]) => {
        webview.addEventListener(eventName, handler);
      });

      // 侦听来自 webview 的消息
      window.addEventListener("message", (event) => {
        if (event.source === webview.contentWindow) {
          const { type, data } = event.data;
          if (type === "webview_info") {
            favicon.src = data.favicon;
            title.textContent = data.title;
          }
        }
      });

      // 注入css样式和js脚本
      webview.addContentScripts([
        {
          name: "nw_inject",
          matches: ["<all_urls>"], // 导航到符合匹配规则的URL时注入
          css: {
            code: `
              ::-webkit-scrollbar {
                width: 12px;
                height: 12px;
              }
              ::-webkit-scrollbar-track {
                background-color: #fcfcfc;
              }
              ::-webkit-scrollbar-thumb {
                background-color: #8b8b8b;
                border-radius: 6px;
                border: 2px solid #fcfcfc;
              }
              ::-webkit-scrollbar-thumb:hover {
                background-color: #636363;
              }
            `,
            // files: ["mystyle.css"],
          },
          js: {
            code: `console.log("Hi, webview!")`,
            // files: ["myscript.js"],
          },
          run_at: "document_start", // 在DOM加载之前注入
          all_frames: true,
        },
      ]);
    </script>

    <script>
      const reloadWatcher = require("node:fs").watch("./", function () {
        reloadWatcher.close();
        nw.Window.get().reload();
      });
    </script>
  </body>
</html>
